package com.cyou.nad.utils;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashSet;
import java.util.LinkedHashSet;

/** 
 * @author 李剑 E-mail: lijian@sohu-rd.com 
 * @version 创建时间：Mar 18, 2009 9:52:12 AM  
 */
public class LogObjectUtils {
	
	/**
	 * 获取一个对象的日志字符串方法
	 * @param logableObject
	 * @return
	 */
	public static String getLogString(Object logableObject){
		try{
			return getLogString(logableObject, new LinkedHashSet<String>());
		}catch(Exception e){
			//e.printStackTrace();
			return "<object>fails to get log string<object>";
		}
	}
	
	
	/**
	 * @param logableObject
	 * @param dealedObjects //已经处理过的队列，防止死锁
	 * @return
	 */
	private static String getLogString(Object logableObject, LinkedHashSet<String> dealedObjects){
		
		if(null == logableObject){
			//--return "<object>null<object>";
			return "{null}"; 
		}
		
		StringBuffer logString = new StringBuffer();
		
		// 1 先加入必要的内容
		/*--
		logString.append("<object ");
		logString.append("toString=\"");
		logString.append(logableObject.toString());
		logString.append("\">");
		*/
		logString.append("{<");
		logString.append(logableObject.toString());
		logString.append(">");
		
		/*
		 * 2 判断本对象是否已经处理过了：
		 *	如果已经处理过了该对象，直接返回给对象的toString内容;
		 *  如果没有处理过该对象，将该对象置为已经处理
		 */
		if(dealedObjects.contains(logableObject.toString())){
			//--logString.append("</object>");
			logString.append("*}");
			return logString.toString();
		}else{			
			dealedObjects.add(logableObject.toString());
		}
		
		/*
		 * 3 获取所有的属性名称以及返回类型 field 
		 * 2009.4.3 修改，因为这种方式得不到父类的属性，因此取消，采用get,set方式匹配
		 */
		/*
		HashMap<String, String> fieldMap = new HashMap<String, String>();
		
		Field[] fields = logableObject.getClass().getDeclaredFields();
		
		for(Field field : fields){
			fieldMap.put(field.getName(), field.getType().getName());
		}
		*/
		
		HashSet<String> setMothedMap = new HashSet<String>();
		
		Method[] setMethods = logableObject.getClass().getMethods();
		String setMethodName = null;
		String setMethodReturnType = null;
		String setFieldName = null;
		for(Method setMethod : setMethods){
			setMethodName = setMethod.getName();
			setMethodReturnType = setMethod.getReturnType().getName();
			if("public".equals(Modifier.toString(setMethod.getModifiers())) && setMethod.getParameterTypes().length > 0 
					&& "void".equals(setMethodReturnType) 
					&& ((setMethodName.startsWith("set") && setMethodName.length() > 3)
					 )){
				setFieldName = setMethodName.substring(3, 4).toLowerCase() + setMethodName.substring(4);
				setMothedMap.add(setFieldName);
			}
		}
		
		/*
		 * 4 遍历所有的方法，寻找匹配的get方法，找到其值
		 */
		Method[] methods = logableObject.getClass().getMethods();
		String methodName = null;
		String returnType = null;
		String fieldName = null;
		Object value  = null;
		for(Method method : methods){
			methodName = method.getName();
			returnType = method.getReturnType().getName();
			if("public".equals(Modifier.toString(method.getModifiers())) && method.getParameterTypes().length == 0 
					&& !"void".equals(returnType) 
					&& ((methodName.startsWith("get") && methodName.length() > 3)
					 || (methodName.startsWith("is") && methodName.length() > 2))){
				//满足条件的方法特征：1 public 方法 2 无参数传入 3 返回类型不为 void 4 方法名以 get 开始 5 方法名长度 > 3
				if(methodName.startsWith("get")){
					fieldName = methodName.substring(3, 4).toLowerCase() + methodName.substring(4);
				}else{
					fieldName = methodName.substring(2, 3).toLowerCase() + methodName.substring(3);
				}
				
				if(setMothedMap.contains(fieldName)){
					//如果匹配结果这个get或者is方法有对应的field属性，则调用其方法获取其值并记录数据
					//--logString.append("<");
					logString.append(fieldName);
					//--logString.append(">");
					logString.append(":");
					try {
						value = method.invoke(logableObject, new Object[]{});
					} catch (Exception e) {
						value = "fails_to_get_value!";
					}
					if(null == value){
						logString.append("null");
					}else{
						logString.append(getValueString(value));
					}
					/*--
					logString.append("</");
					logString.append(fieldName);
					logString.append(">");
					*/
					logString.append(";");
				}
			}
		}
		//--logString.append("</object>");
		logString.append("}");
		return logString.toString();
	}
	
	/**
	 * 针对普通对象，获取其值，暂定为只调用toString方法
	 * @param value
	 * @return
	 */
	private static String getValueString(Object value){
		if(null == value){
			return "null";
		}
		return value.toString();
	}
	
	/**
	 * 比较两个对象，返回不同的属性，只比较基本数据
	 * 暂时只比较第一层的基本数据
	 * @param newObject
	 * @param oldObject
	 * @return
	 */
	public static String getDiffLogString(Object newObject, Object oldObject){
		
		if(null == newObject || null == oldObject || !newObject.getClass().equals(oldObject.getClass())){
			//数据类型不一样，没什么好比较的,返回空值
			return null;
		}
		
		StringBuffer logString = new StringBuffer();
		logString.append("{");
		logString.append("<");
		logString.append(newObject.toString());
		logString.append(">");
		
		HashSet<String> setMothedMap = new HashSet<String>();
		
		Method[] setMethods = newObject.getClass().getMethods();
		String setMethodName = null;
		String setMethodReturnType = null;
		String setFieldName = null;
		for(Method setMethod : setMethods){
			setMethodName = setMethod.getName();
			setMethodReturnType = setMethod.getReturnType().getName();
			if("public".equals(Modifier.toString(setMethod.getModifiers())) && setMethod.getParameterTypes().length > 0 
					&& "void".equals(setMethodReturnType) 
					&& ((setMethodName.startsWith("set") && setMethodName.length() > 3)
					 )){
				setFieldName = setMethodName.substring(3, 4).toLowerCase() + setMethodName.substring(4);
				setMothedMap.add(setFieldName);
			}
		}
		
		Method[] methods = newObject.getClass().getMethods();
		String methodName = null;
		String returnType = null;
		String fieldName = null;
		Object newValue  = null;
		Object oldValue = null;
		for(Method method : methods){
			methodName = method.getName();
			returnType = method.getReturnType().getName();
			if("public".equals(Modifier.toString(method.getModifiers())) && method.getParameterTypes().length == 0 
					&& !"void".equals(returnType) 
					&& ((methodName.startsWith("get") && methodName.length() > 3)
					 || (methodName.startsWith("is") && methodName.length() > 2))){
				//满足条件的方法特征：1 public 方法 2 无参数传入 3 返回类型不为 void 4 方法名以 get 开始 5 方法名长度 > 3
				if(methodName.startsWith("get")){
					fieldName = methodName.substring(3, 4).toLowerCase() + methodName.substring(4);
				}else{
					fieldName = methodName.substring(2, 3).toLowerCase() + methodName.substring(3);
				}
				
				if(setMothedMap.contains(fieldName)){
					//如果get方法满足，则比较两个对象的值，不相同者输出日志
					try {
						newValue = method.invoke(newObject, new Object[]{});
						oldValue = method.invoke(oldObject, new Object[]{});
					} catch (Exception e) {
						logString.append(fieldName);
						logString.append(":error");
						logString.append(";");
						newValue = null;
						oldValue = null;
					}
					if(newValue != null && oldValue != null){
						if(!newValue.toString().equals(oldValue.toString())){
							//不相等，记录日志
							logString.append(fieldName);
							logString.append(":");
							logString.append(oldValue.toString());
							logString.append("->");
							logString.append(newValue.toString());
							logString.append(";");
						}
					}else if(newValue != null && oldValue == null){
						logString.append(fieldName);
						logString.append(":");
						logString.append("null");
						logString.append("->");
						logString.append(newValue.toString());
						logString.append(";");
					}else if(newValue == null && oldValue != null){
						logString.append(fieldName);
						logString.append(":");
						logString.append(oldValue.toString());
						logString.append("->");
						logString.append("null");
						logString.append(";");
					}					
				}
			}
		}
		logString.append("}");
		return logString.toString();
	}
}
